<?php
/**
 * @TODO 未完成,待修改 
 */

/**
 * 这个类在所有的析构函数运行完以后还要调用操作数据库，所以数据库操作类的析构函数不能断开数据库连接
 * 如果要数据库连接类能在析构函数中断开连接，则需要在这个类中使用另外的数据库连接
 *
 */
final class UE_Session_DB {
	protected $_db = null;

	public function __construct() {
		$this->_db = &$GLOBALS['db'];
	}

	public function start() {
		if (ini_get('session.auto_start')) {
			session_destroy();
		    unset($_SESSION);
		}		
		session_set_save_handler(
			array(&$this, 'open'),
			array(&$this, 'close'),
			array(&$this, 'read'),
			array(&$this, 'write'),
			array(&$this, 'destroy'),
			array(&$this, 'gc')
		);
		session_start();
	}

	/**
	 * 运行到 session_start()后程序就进入这个函数
	 *
	 * @param string $savePath
	 * @param string $sessionName
	 * @return bool
	 */
	public function open($savePath, $sessionName){
		return true;
	}

	/**
	 * 程序运行完UE_Session_DB::open()后接着进入这里
	 *
	 * @param string $id
	 * @return bool
	 */
	public function read($sid){
		$sess = $GLOBALS['db']->getOne("SELECT sessdata, ip FROM yl_sessions WHERE sid = '$sid'");
		if(!$sess) {
			return '';
		}

		// 验证IP
		if(UE_IP::realIp() != $sess['ip']) {
			$this->destroy($sid);
			$this->start();
			return '';
		}

		$sessData = $sess['sessdata'];

		if (isset($sessData[255])) {
			$row = $GLOBALS['db']->getOne("SELECT sessdata FROM yl_sessions_data WHERE sid = '$sid'");
			if ($row) {
				$sessData = $row['sessdata'];
			}
		}
		
		return $sessData;
	}

	/**
	 * 当所有析构函数运行完以后程序进入这里
	 *
	 * @param string $id
	 * @param string $sessData
	 * @return bool
	 */
	public function write($sid, $sessData){
		$time = time();
		if (isset($sessData[255])) {
			$this->_db->query("REPLACE INTO `yl_sessions_data` SET sid = '$sid', lastactivity = '$time', sessdata = '$sessData';");
			$sessData = substr($sessData, 255);
		}
		
		extract($_SESSION, EXTR_OVERWRITE);
		
		isset($ip)           || $ip = '';
		isset($uid)          || $uid = 0;
		isset($userName)     || $userName = 'guest';
		isset($password)     || $password = '';
		isset($groupId)      || $groupId = 0;
		isset($adminGroupId) || $adminGroupId = 0;
		isset($invisible)    || $invisible = 0;

		$sql = "REPLACE INTO `yl_sessions`
	 		    SET `sid`          = '$sid',
	 		        `app`          = '" . $_GET['app'] . "',
	 		        `ctl`          = '" . $_GET['ctl'] . "',
	 		        `act`          = '" . $_GET['act'] . "',
	 		        `id`           = '" . $_GET['id'] . "',
	 		        `lastactivity` = '$time',
	 		        `sessData`     = '$sessData',
				    `ip`           = '{$ip}',
	 		        `uid`          = '{$uid}',
	 		        `userName`     = '{$userName}',
	 		        `password`     = '{$password}',
	 		        `groupid`      = '{$groupId}',
	 		        `admingroupid` = '{$adminGroupId}',
	 		        `invisible`    = '{$invisible}';";
		$this->_db->query($sql);

		return true;
	}

	/**
	 * 运行UE_Session_DB::write()以后接着就进入这里，然后退出php进程
	 *
	 * @return bool
	 */
	public function close(){
		$sessionStatFile = DATA_DIR . '/temp/sessionStatFile.php';
		clearstatcache();
		if(!is_file($sessionStatFile) || time() - @filemtime($sessionStatFile) > ini_get('session.gc_maxlifetime')) {
			file_put_contents($sessionStatFile, '', LOCK_EX);
			$this->gc(ini_get('session.gc_maxlifetime'));
		}
		return true;
	}

	public function destroy($sid){
		setcookie(session_name(), '', time() - 3600);
		$_SESSION = array();
		$this->_db->query("DELETE FROM `yl_sessions` WHERE `sid` = '$sid'");
		$this->_db->query("DELETE FROM `yl_sessions_data` WHERE `sid` = '$sid'");
		return true;
	}

	public function gc($maxLifeTime){
		$expire = time() - $maxLifeTime;
		$this->_db->query("DELETE FROM yl_sessions WHERE lastactivity < '$expire'");
		$this->_db->query("DELETE FROM yl_sessions_data WHERE lastactivity < '$expire'");
		return true;
	}
}